home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / sbin / adduser < prev    next >
Text File  |  2009-08-03  |  34KB  |  1,069 lines

  1. #!/usr/bin/perl
  2.  
  3. # adduser: a utility to add users to the system
  4. # addgroup: a utility to add groups to the system
  5. my $version = "3.110ubuntu6";
  6.  
  7. # Copyright (C) 1997, 1998, 1999 Guy Maor <maor@debian.org>
  8. # Copyright (C) 1995 Ted Hajek <tedhajek@boombox.micro.umn.edu>
  9. #                     Ian A. Murdock <imurdock@gnu.ai.mit.edu>
  10. # Bugfixes and other improvements Roland Bauerschmidt <rb@debian.org>
  11. # General scheme of the program adapted by the original debian 'adduser'
  12. #  program by Ian A. Murdock <imurdock@gnu.ai.mit.edu>.
  13. #
  14. #    This program is free software; you can redistribute it and/or modify
  15. #    it under the terms of the GNU General Public License as published by
  16. #    the Free Software Foundation; either version 2 of the License, or
  17. #    (at your option) any later version.
  18. #
  19. #    This program is distributed in the hope that it will be useful,
  20. #    but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22. #    GNU General Public License for more details.
  23. #
  24. #    You should have received a copy of the GNU General Public License
  25. #    along with this program; if not, write to the Free Software
  26. #    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  27. #
  28. #
  29. ####################
  30. # See the usage subroutine for explanation about how the program can be called
  31. ####################
  32.  
  33. use warnings;
  34. use strict;
  35. use Debian::AdduserCommon;
  36. use Getopt::Long;
  37.  
  38. BEGIN {
  39.     local $ENV{PERL_DL_NONLAZY}=1;
  40.     eval 'use Locale::gettext';
  41.     if ($@) {
  42.     *gettext = sub { shift };
  43.     *textdomain = sub { "" };
  44.     *LC_MESSAGES = sub { 5 };
  45.     }
  46.     eval {
  47.     require POSIX;
  48.     import POSIX qw(setlocale);
  49.     };
  50.     if ($@) {
  51.     *setlocale = sub { return 1 };
  52.     }
  53.     eval {
  54.     require I18N::Langinfo;
  55.     import I18N::Langinfo qw(langinfo YESEXPR NOEXPR);
  56.     };
  57.     if ($@) {
  58.     *langinfo = sub { return shift; };
  59.     *YESEXPR  = sub { "^[yY]" };
  60.     *NOEXPR   = sub { "^[nN]" };
  61.     }
  62. }
  63.  
  64. setlocale(LC_MESSAGES, "");
  65. textdomain("adduser");
  66. my $yesexpr = langinfo(YESEXPR());
  67.  
  68. my %config;            # configuration hash
  69.  
  70. my @defaults = ("/etc/adduser.conf");
  71. my $nogroup_id = getgrnam("nogroup") || 65534;
  72. $0 =~ s+.*/++; 
  73.  
  74. our $verbose = 1;        # should we be verbose?
  75. my $allow_badname = 0;        # should we allow bad names?
  76. my $ask_passwd = 1;        # ask for a passwd? 
  77. my $disabled_login = 0;        # leave the new account disabled?
  78.  
  79. our $configfile = undef;
  80. our $found_group_opt = undef;
  81. our $found_sys_opt = undef;
  82. our $ingroup_name = undef;
  83. our $new_firstuid = undef;
  84. our $new_gecos = undef;
  85. our $new_gid = undef;
  86. our $new_lastuid = undef;
  87. our $new_uid = undef;
  88. our $no_create_home = undef;
  89. our $special_home = undef;
  90. our $special_shell = undef;
  91. our $add_extra_groups = 0;
  92. our $encrypt_home = undef;
  93.  
  94. # Global variables we need later
  95. my $existing_user = undef;
  96. my $existing_group = undef;
  97. my $new_name = undef;
  98. my $make_group_also = 0;
  99. my $home_dir = undef;
  100. my $undohome = undef;
  101. my $undouser = undef;
  102. my $undogroup = undef;
  103. my $shell = undef;
  104. my $first_uid = undef;
  105. my $last_uid = undef;
  106. my $dir_mode = undef;
  107. my $perm = undef;
  108.  
  109. our @names;
  110.  
  111. # Parse options, sanity checks
  112. unless ( GetOptions ("quiet|q" => sub { $verbose = 0 },
  113.             "force-badname" => \$allow_badname,
  114.         "help|h" => sub { &usage(); exit 0 },
  115.         "version|v" => sub { &version(); exit 0 },
  116.         "system" => \$found_sys_opt,
  117.         "group" => \$found_group_opt,
  118.         "ingroup=s" => \$ingroup_name,
  119.         "home=s" => \$special_home,
  120.         "gecos=s" => \$new_gecos,
  121.         "shell=s" => \$special_shell,
  122.         "disabled-password" => sub { $ask_passwd = 0 },
  123.         "disabled-login" => sub { $disabled_login = 1; $ask_passwd = 0 },
  124.         "uid=i" => \$new_uid,
  125.         "firstuid=i" => \$new_firstuid,
  126.         "lastuid=i" => \$new_lastuid,
  127.         "gid=i" => \$new_gid,
  128.         "conf=s" => \$configfile,
  129.         "no-create-home" => \$no_create_home,
  130.         "encrypt-home" => \$encrypt_home,
  131.             "add_extra_groups" => \$add_extra_groups,
  132.         "debug" => sub { $verbose = 2 } ) ) {
  133.     &usage();
  134.     exit 1;
  135. }
  136.  
  137. # everyone can issue "--help" and "--version", but only root can go on
  138. dief (gtx("Only root may add a user or group to the system.\n")) if ($> != 0);
  139.  
  140. if( defined($configfile) ) { @defaults = ($configfile); }
  141.  
  142. # detect the right mode
  143. my $action = $0 eq "addgroup" ? "addgroup" : "adduser";
  144. if (defined($found_sys_opt)) {
  145.   $action = "addsysuser" if ($action eq "adduser");
  146.   $action = "addsysgroup" if ($action eq "addgroup");
  147. }
  148.  
  149. # explicitly set PATH, because super (1) cleans up the path and makes adduser unusable;
  150. # this is also a good idea for sudo (which doesn't clean up)
  151. $ENV{"PATH"}="/bin:/usr/bin:/sbin:/usr/sbin";
  152. $ENV{"IFS"}=" \t\n";
  153.  
  154. ############################
  155. # checks related to @names #
  156. ############################
  157.  
  158.  
  159. while (defined(my $arg = shift(@ARGV))) {
  160.   push (@names, $arg);
  161. }
  162.  
  163. if ( (! defined $names[0]) || length($names[0]) == 0 || @names > 2) {
  164.     dief (gtx("Only one or two names allowed.\n"));
  165. }
  166.         
  167.  
  168. if (@names == 2) {    # must be addusertogroup
  169.     dief (gtx("Specify only one name in this mode.\n"))
  170.     if ($action eq "addsysuser" || $found_group_opt);
  171.     $action = "addusertogroup";
  172.     $existing_user = shift (@names);
  173.     $existing_group = shift (@names);
  174. }
  175. else { # 1 parameter, must be adduser
  176.     $new_name = shift (@names);
  177. }
  178.  
  179. ###################################
  180. # check for consistent parameters #
  181. ###################################
  182.  
  183. if ($action ne "addgroup" &&
  184.     defined($found_group_opt) +defined($ingroup_name) +defined($new_gid) > 1 ) {
  185.     dief (gtx("The --group, --ingroup, and --gid options are mutually exclusive.\n"));
  186. }
  187.  
  188.  
  189. if ((defined($special_home)) && ($special_home !~ m+^/+ )) {
  190.   dief (gtx("The home dir must be an absolute path.\n"));
  191. }
  192.        
  193. if (defined($special_home) && $verbose) {
  194.     printf gtx("Warning: The home dir %s you specified already exists.\n"),$special_home
  195.       if (!defined($no_create_home) && -d $special_home);
  196.     printf gtx("Warning: The home dir %s you specified can't be accessed: %s\n"), $special_home, $!
  197.       if (defined($no_create_home) && ! -d $special_home);
  198. }
  199.  
  200.  
  201. if ($found_group_opt) {
  202.     if ($action eq "addsysuser") {
  203.     $make_group_also = 1;
  204.     }
  205.     elsif ($found_sys_opt) {
  206.     $action = "addsysgroup";
  207.     }
  208.     else {
  209.     $action = "addgroup";
  210.     }
  211. }
  212.  
  213. my $ecryptfs_setup_private;
  214. if (defined($encrypt_home)) {
  215.     $ecryptfs_setup_private = &which('ecryptfs-setup-private');
  216. }
  217.  
  218.  
  219. $ENV{"VERBOSE"} = $verbose;
  220. $ENV{"DEBUG"}   = $verbose;
  221.  
  222.  
  223. # preseed configuration data and then read the config file
  224. preseed_config(\@defaults,\%config);
  225.  
  226. &checkname($new_name, $found_sys_opt) if defined $new_name;
  227. $SIG{'INT'} = $SIG{'QUIT'} = $SIG{'HUP'} = 'handler';
  228.  
  229. #####
  230. # OK, we've processed the arguments.  $action equals one of the following,
  231. # and the appropriate variables have been set:
  232. #
  233. # $action = "adduser"
  234. #    $new_name                - the name of the new user.
  235. #    $ingroup_name | $new_gid - the group to add the user to
  236. #    $special_home, $new_uid, $new_gecos - optional overrides
  237. # $action = "addgroup"
  238. #    $new_name                - the name of the new group
  239. #    $new_gid                 - optional override
  240. # $action = "addsysgroup"
  241. #    $new_name                - the name of the new group
  242. #    $new_gid                 - optional override
  243. # $action = "addsysuser"
  244. #    $new_name                - the name of the new user
  245. #    $make_group_also | $ingroup_name | $new_gid | 0  - which group
  246. #    $special_home, $new_uid, $new_gecos - optional overrides
  247. # $action = "addusertogroup"
  248. #    $existing_user           - the user to be added
  249. #    $existing_group          - the group to add her to
  250. #####
  251.  
  252.  
  253. #################
  254. ## addsysgroup ##
  255. #################
  256. if ($action eq "addsysgroup") {
  257.  
  258.     # Check if requested group already exists and we can exit safely
  259.     my $ret = existing_group_ok($new_name, $new_gid);
  260.  
  261.     if ($ret == 3) {
  262.         print STDERR "$0: " if $verbose;
  263.     printf STDERR (gtx("The group `%s' already exists as a system group. Exiting.\n"), $new_name) if $verbose;
  264.     exit 0;
  265.     }
  266.  
  267.     if ($ret == 1) {
  268.         print STDERR "$0: " if $verbose;
  269.     printf STDERR (gtx("The group `%s' already exists and is not a system group. Exiting.\n"), $new_name) if $verbose;
  270.     exit 1;
  271.     }
  272.  
  273.     if ($ret == 2) {
  274.         print STDERR "$0: " if $verbose;
  275.     printf STDERR (gtx("The group `%s' already exists, but has a different GID. Exiting.\n"), $new_name) if $verbose;
  276.     exit 1;
  277.     }
  278.  
  279.     dief (gtx("The GID `%s' is already in use.\n"),$new_gid)
  280.     if (defined($new_gid) && defined(getgrgid($new_gid)));
  281.  
  282.     if (!defined($new_gid)) {
  283.         $new_gid = &first_avail_gid($config{"first_system_gid"},
  284.                    $config{"last_system_gid"});
  285.         if ($new_gid == -1) {
  286.         print STDERR "$0: ";
  287.         printf STDERR gtx("No GID is available in the range %d-%d (FIRST_SYS_GID - LAST_SYS_GID).\n"),$config{"first_system_gid"},$config{"last_system_gid"};
  288.             dief (gtx("The group `%s' was not created.\n"),$new_name);
  289.         }
  290.     }
  291.  
  292.  
  293.     printf (gtx("Adding group `%s' (GID %d) ...\n"),$new_name,$new_gid) if $verbose;
  294.     &invalidate_nscd("group");
  295.     my $groupadd = &which('groupadd');
  296.     &systemcall($groupadd, '-g', $new_gid, $new_name);
  297.     &invalidate_nscd("group");
  298.     print (gtx("Done.\n")) if $verbose;
  299.     exit 0;
  300. }
  301.  
  302.  
  303. ##############
  304. ## addgroup ##
  305. ##############
  306. if ($action eq "addgroup") {
  307.     dief (gtx("The group `%s' already exists.\n"),$new_name)
  308.     if (defined getgrnam($new_name));
  309.     dief (gtx("The GID `%s' is already in use.\n"),$new_gid)
  310.     if (defined($new_gid) && defined(getgrgid($new_gid)));
  311.     if (!defined($new_gid)) {
  312.         $new_gid = &first_avail_gid($config{"first_gid"},
  313.                    $config{"last_gid"});
  314.  
  315.         if ($new_gid == -1) {
  316.         print STDERR "$0: ";
  317.         printf STDERR gtx("No GID is available in the range %d-%d (FIRST_GID - LAST_GID).\n"),$config{"first_gid"},$config{"last_gid"};
  318.             dief (gtx("The group `%s' was not created.\n"),$new_name);
  319.         }
  320.     }
  321.  
  322.     printf (gtx("Adding group `%s' (GID %d) ...\n"),$new_name,$new_gid) if $verbose;
  323.     &invalidate_nscd("group");
  324.     my $groupadd = &which('groupadd');
  325.     &systemcall($groupadd, '-g', $new_gid, $new_name);
  326.     &invalidate_nscd("group");
  327.     print (gtx("Done.\n")) if $verbose;
  328.     exit 0;
  329. }
  330.  
  331.  
  332. ####################
  333. ## addusertogroup ##
  334. ####################
  335. if ($action eq "addusertogroup") {
  336.     dief (gtx("The user `%s' does not exist.\n"),$existing_user)
  337.     if (!defined getpwnam($existing_user));
  338.     dief (gtx("The group `%s' does not exist.\n"),$existing_group)
  339.     if (!defined getgrnam($existing_group));
  340.     if (&user_is_member($existing_user, $existing_group)) {
  341.     printf gtx("The user `%s' is already a member of `%s'.\n"),
  342.                 $existing_user,$existing_group if $verbose;
  343.     exit 0;            # not really an error
  344.     }
  345.  
  346.     printf gtx("Adding user `%s' to group `%s' ...\n"),$existing_user,$existing_group
  347.     if $verbose;
  348.     &invalidate_nscd();
  349.     my $gpasswd = &which('gpasswd');
  350.     &systemcall($gpasswd, '-a',$existing_user,$existing_group);
  351.     &invalidate_nscd();
  352.     print (gtx("Done.\n")) if $verbose;
  353.     exit 0;
  354. }
  355.  
  356.  
  357. ################
  358. ## addsysuser ##
  359. ################
  360. if ($action eq "addsysuser") {
  361.     if (existing_user_ok($new_name, $new_uid) == 1) {
  362.  
  363.         # a user with this name already exists; it's a problem when it's not a system user
  364.         my $tmp_u = getpwnam($new_name);
  365.         if (($tmp_u >= $config{"first_system_uid"}) and ($tmp_u <= $config{"last_system_uid"})) {
  366.         printf (gtx("The system user `%s' already exists. Exiting.\n"), $new_name) if $verbose;
  367.             exit 0;
  368.         }
  369.     printf (gtx("The user `%s' already exists. Exiting.\n"), $new_name) if $verbose;
  370.     exit 1;
  371.     }
  372.     if (existing_user_ok($new_name, $new_uid) == 2) {
  373.     printf (gtx("The user `%s' already exists with a different UID. Exiting.\n"), $new_name) if $verbose;
  374.     exit 1;
  375.     }
  376.  
  377.     if (!$ingroup_name && !defined($new_gid) && !$make_group_also) {
  378.       $new_gid = $nogroup_id;
  379.     }
  380.     check_user_group(1);
  381.  
  382.     if (!defined($new_uid) && $make_group_also) {
  383.     $new_uid = &first_avail_uid($config{"first_system_uid"},
  384.                    $config{"last_system_uid"});
  385.         if ($new_uid == -1) {
  386.         print STDERR "$0: ";
  387.         printf STDERR gtx("No UID/GID pair is available in the range %d-%d (FIRST_SYS_UID - LAST_SYS_UID).\n"),$config{"first_system_uid"},$config{"last_system_uid"};
  388.             dief (gtx("The user `%s' was not created.\n"),$new_name);
  389.         }
  390.         $new_gid = &first_avail_gid($config{"first_system_gid"},
  391.                                 $config{"last_system_gid"});
  392.     $ingroup_name = $new_name;
  393.     }
  394.     elsif (!defined($new_uid) && !$make_group_also) {
  395.     $new_uid = &first_avail_uid($config{"first_system_uid"},
  396.                    $config{"last_system_uid"});
  397.         if ($new_uid == -1) {
  398.         print STDERR "$0: ";
  399.         printf STDERR gtx("No UID is available in the range %d-%d (FIRST_SYS_UID - LAST_SYS_UID).\n"),$config{"first_system_uid"},$config{"last_system_uid"};
  400.         dief (gtx("The user `%s' was not created.\n"),$new_name);
  401.         }
  402.         if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); }
  403.     elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); }
  404.     else { dief (gtx("Internal error")); }
  405.     }
  406.     else {
  407.     if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); }
  408.     elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); }
  409.     elsif ($make_group_also){ $new_gid=$new_uid; $ingroup_name=$new_name; }
  410.     else { dief (gtx("Internal error")); }
  411.     }
  412.     printf (gtx("Adding system user `%s' (UID %d) ...\n"),$new_name,$new_uid) if $verbose;
  413.  
  414.     &invalidate_nscd();
  415.     # if we reach this point, and the group does already exist, we can use it.
  416.     if ($make_group_also && !getgrnam($new_name)) {
  417.     printf (gtx("Adding new group `%s' (GID %d) ...\n"),$new_name,$new_gid) if $verbose;
  418.     $undogroup = $new_name;
  419.        my $groupadd = &which('groupadd');
  420.     &systemcall($groupadd, '-g', $new_gid, $new_name);
  421.     &invalidate_nscd("group");
  422.     }
  423.  
  424.     printf gtx("Adding new user `%s' (UID %d) with group `%s' ...\n"),$new_name,$new_uid,$ingroup_name
  425.     if $verbose;
  426.     $home_dir = $special_home || &homedir($new_name, $ingroup_name);
  427.     $shell = $special_shell || '/bin/false';
  428.     $undouser = $new_name;
  429.     my $useradd = &which('useradd');
  430.     &systemcall($useradd, '-d', $home_dir, '-g', $ingroup_name, '-s',
  431.         $shell, '-u', $new_uid, $new_name);
  432.     if(!$disabled_login) {
  433.         my $usermod = &which('usermod');
  434.         &systemcall($usermod, '-p', '*', $new_name);
  435.     }
  436.     my $chage = &which('chage');
  437.     print "$chage -M 99999 $new_name\n" if ($verbose > 1);
  438.     # do _not_ use systemcall() here, since systemcall() dies on
  439.     # non-zero exit code and we need to do special handling here!
  440.     if (system($chage, '-M', '99999', $new_name)) {
  441.     if( ($?>>8) ne 15 ) {
  442.         &cleanup(sprintf((gtx("`%s' returned error code %d. Exiting.\n")), "$chage -M 99999 $new_name", $?>>8))
  443.           if ($?>>8);
  444.         &cleanup(sprintf((gtx("`%s' exited from signal %d. Exiting.\n")), "$chage -M 99999 $new_name", $?&255));
  445.     } else {
  446.         printf (gtx("%s failed with return code 15, shadow not enabled, password aging cannot be set. Continuing.\n"), $chage);
  447.     }
  448.     }
  449.     &invalidate_nscd();
  450.  
  451.     if(defined($new_gecos)) {
  452.     &ch_gecos($new_gecos);
  453.     }
  454.     create_homedir (0);
  455.  
  456.     exit 0;
  457. }
  458.  
  459.  
  460. #############
  461. ## adduser ##
  462. #############
  463. if ($action eq "adduser") {
  464.     if (!$ingroup_name && !defined($new_gid)) {
  465.     if ($config{"usergroups"} =~  /yes/i) { $make_group_also = 1; }
  466.     else { $new_gid = $config{"users_gid"}; }
  467.     }
  468.     check_user_group(0);
  469.     $first_uid = $new_firstuid || $config{"first_uid"};
  470.     $last_uid = $new_lastuid || $config{"last_uid"};
  471.     printf (gtx("Adding user `%s' ...\n"),$new_name) if $verbose;
  472.  
  473.     if (!defined($new_uid) && $make_group_also) {
  474.     $new_uid = &first_avail_uid($first_uid,
  475.                    $last_uid);
  476.                 
  477.         if ($new_uid == -1) {
  478.         print STDERR "$0: ";
  479.             printf STDERR gtx("No UID/GID pair is available in the range %d-%d (FIRST_UID - LAST_UID).\n"),$first_uid,$last_uid;
  480.         dief (gtx("The user `%s' was not created.\n"),$new_name);
  481.         }
  482.     $new_gid = &first_avail_gid($config{"first_gid"}, 
  483.                                 $config{"last_gid"});
  484.     $ingroup_name = $new_name;
  485.     }
  486.     elsif (!defined($new_uid) && !$make_group_also) {
  487.     $new_uid = &first_avail_uid($first_uid,
  488.                    $last_uid);
  489.     if ($new_uid == -1) {
  490.         print STDERR "$0: ";
  491.         printf STDERR gtx("No UID is available in the range %d-%d (FIRST_UID - LAST_UID).\n"),$config{"first_uid"},$config{"last_uid"};
  492.             dief (gtx("The user `%s' was not created.\n"),$new_name);
  493.         }
  494.     if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); }
  495.     elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); }
  496.     else { dief (gtx("Internal error")); }
  497.     }
  498.     else {
  499.     if (defined($new_gid)) { $ingroup_name = getgrgid($new_gid); }
  500.     elsif ($ingroup_name) { $new_gid = getgrnam($ingroup_name); }
  501.     elsif ($make_group_also){ $new_gid=$new_uid; $ingroup_name=$new_name; }
  502.     else { dief (gtx("Internal error")); }
  503.     }
  504.  
  505.     &invalidate_nscd();
  506.     if ($make_group_also) {
  507.     printf (gtx("Adding new group `%s' (%d) ...\n"),$new_name,$new_gid) if $verbose;
  508.     $undogroup = $new_name;
  509.         my $groupadd = &which('groupadd');
  510.     &systemcall($groupadd, '-g', $new_gid, $new_name);
  511.     &invalidate_nscd();
  512.     }
  513.  
  514.     printf gtx("Adding new user `%s' (%d) with group `%s' ...\n"),$new_name,$new_uid,$ingroup_name
  515.     if $verbose;
  516.     $home_dir = $special_home || &homedir($new_name, $ingroup_name);
  517.     $shell = $special_shell || $config{"dshell"};
  518.     $undouser = $new_name;
  519.     my $useradd = &which('useradd');
  520.     &systemcall($useradd, '-d', $home_dir, '-g', $ingroup_name, '-s',
  521.         $shell, '-u', $new_uid, $new_name);
  522.     &invalidate_nscd();
  523.  
  524.     create_homedir (1); # copy skeleton data
  525.  
  526.     # useradd without -p has left the account disabled (password string is '!')
  527.     my $yesexpr = langinfo(YESEXPR());
  528.     if ($ask_passwd) {
  529.     for (;;) {
  530.           my $passwd = &which('passwd');
  531.       # do _not_ use systemcall() here, since systemcall() dies on
  532.       # non-zero exit code and we need to do special handling here!
  533.           system($passwd, $new_name);
  534.       my $ok = $?>>8;
  535.       if ($ok != 0) {
  536.             my $answer;
  537.             # hm, error, should we break now?
  538.         print (gtx("Permission denied\n")) if ($ok == 1);
  539.         print (gtx("invalid combination of options\n")) if ($ok == 2);
  540.         print (gtx("unexpected failure, nothing done\n")) if ($ok == 3);
  541.         print (gtx("unexpected failure, passwd file missing\n")) if ($ok == 4);
  542.         print (gtx("passwd file busy, try again\n")) if ($ok == 5);
  543.         print (gtx("invalid argument to option\n")) if ($ok == 6);
  544.         
  545.         # Translators: [y/N] has to be replaced by values defined in your
  546.         # locale.  You can see by running "locale noexpr" which regular
  547.         # expression will be checked to find positive answer.
  548.         print (gtx("Try again? [y/N] "));
  549.         chop ($answer=<STDIN>);
  550.         last if ($answer !~ m/$yesexpr/o);
  551.       }
  552.       else {
  553.         last; ## passwd ok
  554.       }
  555.     }
  556.     } else {
  557.     if(!$disabled_login) {
  558.            my $usermod = &which('usermod');
  559.         &systemcall($usermod, '-p', '*', $new_name);
  560.     }
  561.     }
  562.  
  563.     if (defined($new_gecos)) {
  564.     &ch_gecos($new_gecos);
  565.     }
  566.     else {
  567.     my $noexpr = langinfo(NOEXPR());
  568.     for (;;) {
  569.            my $chfn = &which('chfn');
  570.         &systemcall($chfn, $new_name);
  571.         # Translators: [y/N] has to be replaced by values defined in your
  572.         # locale.  You can see by running "locale yesexpr" which regular
  573.         # expression will be checked to find positive answer.
  574.         print (gtx("Is the information correct? [Y/n] "));
  575.         chop (my $answer=<STDIN>);
  576.         last if ($answer !~ m/$noexpr/o);
  577.     }
  578.     }
  579.  
  580.     if ( ( $add_extra_groups || $config{"add_extra_groups"} ) && defined($config{"extra_groups"}) ) {
  581.         printf (gtx("Adding new user `%s' to extra groups ...\n"), $new_name);
  582.         foreach my $newgrp ( split ' ', $config{"extra_groups"} ) {
  583.             if (!defined getgrnam($newgrp)) {
  584.                 warnf (gtx("The group `%s' does not exist.\n"),$newgrp);
  585.                 next;
  586.             }
  587.             if (&user_is_member($new_name, $newgrp)) {
  588.                 printf gtx("The user `%s' is already a member of `%s'.\n"),
  589.                         $new_name,$newgrp if $verbose;
  590.                 next;
  591.  
  592.             }
  593.  
  594.             printf gtx("Adding user `%s' to group `%s' ...\n"),$new_name,$newgrp
  595.                 if $verbose;
  596.             &invalidate_nscd();
  597.             my $gpasswd = &which('gpasswd');
  598.             &systemcall($gpasswd, '-M',
  599.                         join(',', get_group_members($newgrp), $new_name),
  600.                         $newgrp);
  601.             &invalidate_nscd();
  602.         }
  603.     }
  604.  
  605.  
  606.     if ($config{"quotauser"}) {
  607.     printf (gtx("Setting quota for user `%s' to values of user `%s' ...\n"), $new_name, $config{quotauser});
  608.     my $edquota = &which('edquota');
  609.     &systemcall($edquota, '-p', $config{quotauser}, $new_name);
  610.     }
  611.  
  612.     &systemcall('/usr/local/sbin/adduser.local', $new_name, $new_uid,
  613.         $new_gid, $home_dir) if (-x "/usr/local/sbin/adduser.local");
  614.     
  615.     exit 0;
  616. }
  617.  
  618. #
  619. # we never go here
  620. #
  621.  
  622.  
  623. # calculate home directory
  624. sub homedir {
  625.     my $dir = $config{"dhome"};
  626.     $dir .= '/' . $_[1] if ($config{"grouphomes"} =~ /yes/i);
  627.     $dir .= '/' . substr($_[0],0,1) if ($config{"letterhomes"} =~ /yes/i);
  628.     $dir .= '/' . $_[0];
  629.     return $dir;
  630. }
  631.  
  632.  
  633. # create_homedir -- create the homedirectory
  634. # parameter 
  635. #   1: $copy_skeleton: 
  636. #     if 0  -> don't copy the skeleton data
  637. #     if 1  -> copy the files in /etc/skel to the newly created home directory
  638. # return values:
  639. #   none
  640. sub create_homedir {
  641.   my ($copy_skeleton) = @_;
  642.  
  643.   if ($no_create_home) {
  644.       printf gtx("Not creating home directory `%s'.\n"), $home_dir if $verbose;
  645.   }
  646.   elsif (-e $home_dir) {
  647.       printf gtx("The home directory `%s' already exists.  Not copying from `%s'.\n"),
  648.       $home_dir,$config{skel} if $verbose && !$no_create_home;
  649.       my @homedir_stat = stat($home_dir);
  650.       my $home_uid = $homedir_stat[4];
  651.       my $home_gid = $homedir_stat[5];
  652.       if (($home_uid != $new_uid) || ($home_gid != $new_gid)) {
  653.       warnf gtx("Warning: The home directory `%s' does not belong to the user you are currently creating.\n"), $home_dir;
  654.       }
  655.       undef @homedir_stat; undef $home_uid; undef $home_gid;
  656.   }
  657.   else {
  658.       printf gtx("Creating home directory `%s' ...\n"),$home_dir if $verbose;
  659.       $undohome = $home_dir;
  660.       &mktree($home_dir) || &cleanup(sprintf(gtx("Couldn't create home directory `%s': %s.\n"), $home_dir, $!));
  661.       chown($new_uid, $new_gid, $home_dir)
  662.       || &cleanup("chown $new_uid:$new_gid $home_dir: $!\n");
  663.       $dir_mode = get_dir_mode($make_group_also);
  664.       chmod ($dir_mode, $home_dir) ||
  665.       &cleanup("chmod $dir_mode $home_dir: $!\n");
  666.  
  667.       if (defined($encrypt_home)) {
  668.     printf gtx("Setting up encryption ...\n") if $verbose;
  669.     &systemcall($ecryptfs_setup_private, '-b', '-u', $new_name);
  670.       }
  671.  
  672.       if ($config{"skel"} && $copy_skeleton) {
  673.       printf gtx("Copying files from `%s' ...\n"),$config{skel} if $verbose;
  674.       open(FIND, "cd $config{skel}; find .  -print |")
  675.           || &cleanup(sprintf(gtx("fork for `find' failed: %s\n"), $!));
  676.       while (<FIND>) {
  677.           chop;
  678.           next if ($_ eq ".");
  679.           next if ($_ =~ qr/$config{skel_ignore_regex}/ );
  680.           ©_to_dir($config{"skel"}, $_, $home_dir, $new_uid,
  681.                 $new_gid, ($config{"setgid_home"} =~ /yes/i));
  682.       }
  683.       }
  684.  
  685.       if (defined($encrypt_home)) {
  686.       &systemcall("/bin/umount", $home_dir);
  687.       }
  688.   }
  689. }
  690.  
  691. # mktree: create a directory and all parent directories, we don't care about the rights and so on
  692. # parameters:
  693. #   tree: the path 
  694. # return values:
  695. #   none
  696. sub mktree {
  697.     my($tree) = @_;
  698.     my($done, @path);
  699.     my $default_dir_mode = 0755;
  700.  
  701.     $tree =~ s:^/*(.*)/*$:$1:; # chop off leading & trailing slashes
  702.     @path = split(/\//, $tree);
  703.  
  704.     $done = "";
  705.     while (@path) {
  706.     $done .= '/' . shift(@path);
  707.     -d $done || mkdir($done, $default_dir_mode) || return 0;
  708.     }
  709.     return 1;
  710. }
  711.  
  712. # existing_user_ok: check if there's already a user present on the system which satisfies the requirements
  713. # parameter:
  714. #   new_name: the name of the user to check
  715. #   new_uid : the UID of the user
  716. # return values:
  717. #   0 if the the user doesn't exist 
  718. #   1 if the user already exists with the specified uid (or $new_uid wasn't specified)
  719. #   2 if the user already exists, but $new_uid doesn't matches its uid 
  720. sub existing_user_ok {
  721.     my($new_name,$new_uid) = @_;
  722.     my ($dummy1,$dummy2,$uid);
  723.     if (($dummy1,$dummy2,$uid) = getpwnam($new_name)) {
  724.     if( defined($new_uid) && $uid == $new_uid ) {
  725.         return 1;
  726.     }
  727.     if (! defined($new_uid)) { 
  728.         return 1;
  729.     }
  730.         # TODO: do we really need this code? Range check shouldn't performed here
  731.     if( $uid >= $config{"first_system_uid"} &&
  732.         $uid <= $config{"last_system_uid" } ) {
  733.         return 2;
  734.     }
  735.     } else {
  736.     return 0;
  737.     }
  738. }
  739.  
  740. # existing_group_ok: check if there's already a group which satiesfies the requirements
  741. # parameter:
  742. #   new_name: the name of the group
  743. #   new_gid : the UID of the group
  744. # return values:
  745. #   0 if the group doesn't exist
  746. #   1 if the group already exists with the specified gid (or $new_gid wasn't specified)
  747. #   2 if the group already exists, but $new_gid doesn't match its gid 
  748. #   3 if the group already exists inside the system range
  749. sub existing_group_ok {
  750.     my($new_name,$new_gid) = @_;
  751.     my ($dummy1,$dummy2,$gid);
  752.     if (($dummy1,$dummy2,$gid) = getgrnam($new_name)) {
  753.  
  754.         # TODO: is this check required? There shouldn't be any gid outside of our allowed range anyways ...
  755.     if( $gid >= $config{"first_system_gid"} &&
  756.         $gid <= $config{"last_system_gid" } ) {
  757.         return 3;
  758.     }
  759.     if (! defined($new_gid)) {
  760.         return 1;
  761.     }
  762.         if ($gid == $new_gid) {
  763.             return 1;
  764.     } else {
  765.             return 2;
  766.         }
  767.     } else {
  768.     return 0;
  769.     }
  770. }
  771.  
  772.  
  773.  
  774. # check_user_group: ???
  775. # parameters:
  776. #   system: 0 if the user isn't a system user, 1 otherwise
  777. # return values:
  778. #   
  779. sub check_user_group {
  780.     my ($system) = @_;
  781.     if( !$system || !existing_user_ok($new_name, $new_uid) ) {
  782.     if( defined getpwnam($new_name) ) {
  783.         if( $system ) {
  784.         dief (gtx("The user `%s' already exists, and is not a system user.\n"),$new_name);
  785.         } else {
  786.         dief (gtx("The user `%s' already exists.\n"),$new_name);
  787.         }
  788.     }
  789.     dief (gtx("The UID %d is already in use.\n"),$new_uid)
  790.       if (defined($new_uid) && getpwuid($new_uid));
  791.     }
  792.     if ($make_group_also) {
  793.     if( !$system || !existing_group_ok($new_name, $new_uid) ) {
  794.         dief (gtx("The group `%s' already exists.\n"),$new_name)
  795.           if (defined getgrnam($new_name));
  796.         dief (gtx("The GID %d is already in use.\n"),$new_uid)
  797.           if (defined($new_uid) && defined(getgrgid($new_uid)));
  798.     }
  799.     }
  800.     else {
  801.     dief (gtx("The group `%s' does not exist.\n"),$ingroup_name)
  802.         if ($ingroup_name && !defined(getgrnam($ingroup_name)));
  803.     dief (gtx("The GID %d does not exist.\n"),$new_gid)
  804.         if (defined($new_gid) && !defined(getgrgid($new_gid)));
  805.     }
  806. }
  807.  
  808.  
  809. # copy_to_dir :
  810. # parameters:
  811. #   fromdir
  812. #   file
  813. #   todir
  814. #   newi
  815. #   newg
  816. #   sgiddir
  817. # return values:
  818. #   none
  819. sub copy_to_dir {
  820.     my($fromdir, $file, $todir, $newu, $newg, $sgiddir) = @_;
  821.  
  822.     if (-l "$fromdir/$file") {
  823.     my $target=readlink("$fromdir/$file") or &cleanup("readlink: $!\n");
  824.     my $curgid="$)";
  825.     my $curuid="$>";
  826.     my $error="";
  827.     $)="$newg";
  828.     $>="$newu";
  829.     symlink("$target", "$todir/$file") or $error="$!";
  830.         $>="$curuid";
  831.         $)="$curgid";
  832.     if( "$error" ne "" ) {
  833.         &cleanup("symlink: $!\n");
  834.     }
  835.     return;
  836.     }
  837.     elsif (-f "$fromdir/$file") {
  838.     open (FILE, "$fromdir/$file") || &cleanup("open $fromdir/$file: $!");
  839.     open (NEWFILE, ">$todir/$file") || &cleanup("open >$todir/$file: $!");
  840.  
  841.     (print NEWFILE <FILE>) || &cleanup("print $todir/$file: $!");
  842.     close FILE;
  843.     close(NEWFILE)  || &cleanup("close $todir/$file ");
  844.  
  845.     }
  846.     elsif (-d "$fromdir/$file") {
  847.     mkdir("$todir/$file", 700) || &cleanup("mkdir: $!");
  848.     }
  849.     else {
  850.     &cleanup(sprintf((gtx("Cannot deal with %s.\nIt is not a dir, file, or symlink.\n")), "$fromdir/$file"));
  851.     }
  852.     
  853.     chown($newu, $newg, "$todir/$file")
  854.     || &cleanup("chown $newu:$newg $todir/$file: $!\n");
  855.     $perm = (stat("$fromdir/$file"))[2] & 07777;
  856.     $perm |= 02000 if (-d "$fromdir/$file" && ($perm & 010) && $sgiddir);
  857.     chmod($perm, "$todir/$file") || &cleanup("chmod $todir/$file: $!\n");
  858. }
  859.        
  860.  
  861. # checkname: perform some sanity checks
  862. # parameters:
  863. #   name: the name to check
  864. #   system: 0 if the user isn't a system user, 1 otherwise
  865. # return values:
  866. #   none (exits on error)
  867. sub checkname {
  868.     my ($name, $system) = @_;
  869.     if ($name !~ /^[_.A-Za-z0-9][-\@_.A-Za-z0-9]*\$?$/) {
  870.     printf STDERR
  871. (gtx("%s: To avoid problems, the username should consist only of
  872. letters, digits, underscores, periods, at signs and dashes, and not start with
  873. a dash (as defined by IEEE Std 1003.1-2001). For compatibility with Samba
  874. machine accounts \$ is also supported at the end of the username\n"), $0);
  875.         exit 1;
  876.     }
  877.     if ($system
  878.         ? $name !~ qr/$config{"name_regex_system"}/
  879.         : $name !~ qr/$config{"name_regex"}/) {
  880.       if ($allow_badname) {
  881.     print (gtx("Allowing use of questionable username.\n")) if ($verbose);
  882.       }
  883.       else {
  884.         printf STDERR
  885. (gtx("%s: Please enter a username matching the regular expression configured
  886. via the NAME_REGEX[_SYSTEM] configuration variable.  Use the `--force-badname'
  887. option to relax this check or reconfigure NAME_REGEX or NAME_REGEX_SYSTEM.\n"), $0);
  888.         exit 1;
  889.       }
  890.     }
  891. }
  892.  
  893. # first_avail_uid: return the first available uid in given range
  894. # parameters:
  895. #   min, max: the range
  896. # return values:
  897. #   -1 if no free uid is available
  898. #  otherwise the choosen uid
  899. sub first_avail_uid {
  900.     my ($min, $max) = @_;
  901.     printf (gtx("Selecting UID from range %d to %d ...\n"),$min,$max) if ($verbose > 1);
  902.  
  903.     my $t = $min;
  904.     while ($t <= $max) {
  905.        return $t if (!defined(getpwuid($t)));
  906.        $t++;
  907.     }
  908.     return -1; # nothing available
  909. }
  910.  
  911. # first_avail_gid: return the first available gid in given range
  912. # parameters:
  913. #   min, max: the range
  914. # return values:
  915. #   -1 if no free gid is available
  916. #   otherwise the choosen gid
  917. sub first_avail_gid {
  918.     my ($min, $max) = @_;
  919.     printf (gtx("Selecting GID from range %d to %d ...\n"),$min,$max) if ($verbose > 1);
  920.  
  921.     my $t = $min;
  922.     while ($t <= $max) {
  923.        return $t if (!defined(getgrgid($t)));
  924.        $t++;
  925.     }
  926.     return -1; # nothing available
  927. }
  928.  
  929. sub ch_gecos {
  930.     my $chfn = &which('chfn');
  931.     my $gecos = shift;
  932.     if($gecos =~ /,/)
  933.       {
  934.       my($gecos_name,$gecos_room,$gecos_work,$gecos_home,$gecos_other)
  935.         = split(/,/,$gecos);
  936.  
  937.       &systemcall($chfn, '-f', $gecos_name, '-r', $gecos_room, $new_name);
  938.       &systemcall($chfn,'-w',$gecos_work,$new_name)
  939.         if(defined($gecos_work));
  940.       &systemcall($chfn,'-h',$gecos_home,$new_name)
  941.         if(defined($gecos_home));
  942.       &systemcall($chfn,'-o',$gecos_other,$new_name)
  943.         if(defined($gecos_other));
  944.       }
  945.     else
  946.       {
  947.       &systemcall($chfn, '-f', $gecos, $new_name);
  948.       }
  949. }
  950.  
  951. # user is member of group?
  952. sub user_is_member {
  953.     my($user, $group) = @_;
  954.     for (split(/ /, (getgrnam($group))[3])) {
  955.     return 1 if ($user eq $_);
  956.     }
  957.     return 0;
  958. }
  959.  
  960.  
  961. sub cleanup {
  962.     my ($msg) = @_;
  963.     printf (gtx("Stopped: %s\n"),$msg);
  964.     if ($undohome) {
  965.     printf (gtx("Removing directory `%s' ...\n"),$undohome);
  966.     &systemcall('rm', '-rf', $undohome);
  967.     }
  968.     if ($undouser) {
  969.     printf (gtx("Removing user `%s' ...\n"),$undouser);
  970.     &systemcall('userdel', $undouser);
  971.     }
  972.     if ($undogroup) {
  973.     printf (gtx("Removing group `%s' ...\n"),$undogroup);
  974.     &systemcall('groupdel', $undogroup);
  975.     }
  976.     # do we need to invalidate the nscd cache here, too?
  977.     exit 1;
  978. }
  979.  
  980. sub handler {
  981.     my($sig) = @_;
  982.     # Translators: the variable %s is INT, QUIT, or HUP.
  983.     # Please do not insert a space character between SIG and %s.
  984.     &cleanup(sprintf(gtx("Caught a SIG%s.\n"), $sig));
  985. }
  986.     
  987.  
  988. sub version {
  989.     printf (gtx("adduser version %s\n\n"), $version);
  990.     print gtx("Adds a user or group to the system.
  991.   
  992. Copyright (C) 1997, 1998, 1999 Guy Maor <maor\@debian.org>
  993. Copyright (C) 1995 Ian Murdock <imurdock\@gnu.ai.mit.edu>,
  994.                    Ted Hajek <tedhajek\@boombox.micro.umn.edu>
  995. \n");
  996.     print gtx(
  997. "This program is free software; you can redistribute it and/or modify
  998. it under the terms of the GNU General Public License as published by
  999. the Free Software Foundation; either version 2 of the License, or (at
  1000. your option) any later version.
  1001.  
  1002. This program is distributed in the hope that it will be useful, but
  1003. WITHOUT ANY WARRANTY; without even the implied warranty of
  1004. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  1005. General Public License, /usr/share/common-licenses/GPL, for more details.
  1006. ");
  1007. }
  1008.  
  1009. sub usage {
  1010.     printf gtx(
  1011. "adduser [--home DIR] [--shell SHELL] [--no-create-home] [--uid ID]
  1012. [--firstuid ID] [--lastuid ID] [--gecos GECOS] [--ingroup GROUP | --gid ID]
  1013. [--disabled-password] [--disabled-login] [--encrypt-home] USER
  1014.    Add a normal user
  1015.  
  1016. adduser --system [--home DIR] [--shell SHELL] [--no-create-home] [--uid ID]
  1017. [--gecos GECOS] [--group | --ingroup GROUP | --gid ID] [--disabled-password]
  1018. [--disabled-login] USER
  1019.    Add a system user
  1020.  
  1021. adduser --group [--gid ID] GROUP
  1022. addgroup [--gid ID] GROUP
  1023.    Add a user group
  1024.  
  1025. addgroup --system [--gid ID] GROUP
  1026.    Add a system group
  1027.  
  1028. adduser USER GROUP
  1029.    Add an existing user to an existing group
  1030.  
  1031. general options:
  1032.   --quiet | -q      don't give process information to stdout
  1033.   --force-badname   allow usernames which do not match the
  1034.                     NAME_REGEX[_SYSTEM] configuration variable
  1035.   --help | -h       usage message
  1036.   --version | -v    version number and copyright
  1037.   --conf | -c FILE  use FILE as configuration file\n\n");
  1038. }
  1039.  
  1040. sub get_dir_mode
  1041.   {
  1042.       my $setgid = shift;
  1043.       # no longer make home directories setgid per default (closes: #64806)
  1044.       $setgid = 0 unless $config{"setgid_home"} =~  /yes/i;
  1045.  
  1046.       my $dir_mode = $config{"dir_mode"};
  1047.       if(!defined($dir_mode) || ! ($dir_mode =~ /[0-7]{3}/ ||
  1048.                    $dir_mode =~ /[0-7]{4}/))
  1049.     {
  1050.         $dir_mode = $setgid ? 2755 : 0755;
  1051.     }
  1052.       else
  1053.     {
  1054.         $dir_mode = $config{"dir_mode"};
  1055.         if($setgid && (length($dir_mode) == 3 || $dir_mode =~ /^[0-1|4-5][0-7]{3}$/))
  1056.           {
  1057.           $dir_mode += 2000;
  1058.           }
  1059.     }
  1060.       return oct($dir_mode);
  1061.   }
  1062.  
  1063. # Local Variables:
  1064. # mode:cperl
  1065. # cperl-indent-level:4
  1066. # End:
  1067.  
  1068. # vim:set ai et sts=4 sw=4 tw=0:
  1069.